package demoMod.anm2editor.ui;

import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.Input;
import com.badlogic.gdx.graphics.Color;
import com.badlogic.gdx.graphics.Texture;
import com.badlogic.gdx.graphics.g2d.BitmapFont;
import demoMod.anm2editor.fonts.FontKeys;
import demoMod.anm2editor.localization.LocalizedStrings;
import demoMod.anm2editor.model.*;
import demoMod.gdxform.core.FormManager;
import demoMod.gdxform.enums.GFrameCloseStrategy;
import demoMod.gdxform.enums.GFrameWindowMode;
import demoMod.gdxform.enums.GFrameWindowStyle;
import demoMod.gdxform.helpers.FontHelper;
import demoMod.gdxform.ui.GButton;
import demoMod.gdxform.ui.GFrame;
import demoMod.gdxform.ui.GLabel;
import demoMod.gdxform.ui.GTextField;

import java.util.ArrayList;
import java.util.List;
import java.util.function.Supplier;
import java.util.stream.Collectors;

public class AdjustKeyframePropertyWindow extends GFrame {
    private final HistoryPanel historyPanel;
    private Track targetTrack;
    private final int startFrameIndex;
    private int endFrameIndex;
    private boolean confirmed = false;

    private final Supplier<Tuple3<Float, Float, Float>> defaultFloatFunctionProvider = () -> new Tuple3<>(0.0F, 0.0F, 100.0F); //基础值偏移, 比例调整基准值, 比例度(%)
    private final Supplier<Tuple3<Integer, Integer, Float>> defaultIntFunctionProvider = () -> new Tuple3<>(0, 0, 100.0F); //基础值偏移, 比例调整基准值, 比例度(%)
    private final Supplier<Tuple3<Boolean, Boolean, Boolean>> defaultBooleanFunctionProvider = () -> new Tuple3<>(false, false, false); //取反, 全勾选, 全不勾选

    private final Tuple3<Float, Float, Float> xPosFunc = defaultFloatFunctionProvider.get();
    private final Tuple3<Float, Float, Float> yPosFunc = defaultFloatFunctionProvider.get();
    private final Tuple3<Float, Float, Float> xOriginFunc = defaultFloatFunctionProvider.get();
    private final Tuple3<Float, Float, Float> yOriginFunc = defaultFloatFunctionProvider.get();
    private final Tuple3<Integer, Integer, Float> xSrcFunc = defaultIntFunctionProvider.get();
    private final Tuple3<Integer, Integer, Float> ySrcFunc = defaultIntFunctionProvider.get();
    private final Tuple3<Integer, Integer, Float> srcWidthFunc = defaultIntFunctionProvider.get();
    private final Tuple3<Integer, Integer, Float> srcHeightFunc = defaultIntFunctionProvider.get();
    private final Tuple3<Float, Float, Float> xScaleFunc = defaultFloatFunctionProvider.get();
    private final Tuple3<Float, Float, Float> yScaleFunc = defaultFloatFunctionProvider.get();
    private final Tuple3<Float, Float, Float> rotationFunc = defaultFloatFunctionProvider.get();
    private final Tuple3<Boolean, Boolean, Boolean> visibleFunc = defaultBooleanFunctionProvider.get();
    private final Tuple3<Integer, Integer, Float> tintRFunc = defaultIntFunctionProvider.get();
    private final Tuple3<Integer, Integer, Float> tintGFunc = defaultIntFunctionProvider.get();
    private final Tuple3<Integer, Integer, Float> tintBFunc = defaultIntFunctionProvider.get();
    private final Tuple3<Integer, Integer, Float> tintAFunc = defaultIntFunctionProvider.get();
    private final Tuple3<Integer, Integer, Float> colorOffsetRCurve = defaultIntFunctionProvider.get();
    private final Tuple3<Integer, Integer, Float> colorOffsetGCurve = defaultIntFunctionProvider.get();
    private final Tuple3<Integer, Integer, Float> colorOffsetBCurve = defaultIntFunctionProvider.get();
    private final Tuple3<Boolean, Boolean, Boolean> interpolationFunc = defaultBooleanFunctionProvider.get();

    public AdjustKeyframePropertyWindow(BitmapFont bannerFont) {
        super(Gdx.graphics.getWidth() / 2.0F - Gdx.graphics.getWidth() * 0.075F, Gdx.graphics.getHeight() / 2.0F - Gdx.graphics.getHeight() * 0.3F, Gdx.graphics.getWidth() * 0.15F, Gdx.graphics.getHeight() * 0.6F - 45, FontHelper.getFont(FontKeys.SIM_HEI_14), GFrameWindowStyle.CLOSE_BUTTON_ONLY, false);
        setWindowMode(GFrameWindowMode.MODAL);
        Timeline timeline = ((Timeline) FormManager.getInstance().getContainerById(Timeline.ID));
        historyPanel = (HistoryPanel) FormManager.getInstance().getContainerById(HistoryPanel.ID);
        startFrameIndex = timeline.getPointerIndex();
        List<String> strings = LocalizedStrings.getStrings("AdjustKeyframePropertyWindow");
        setTitle(strings.get(0));
        setResizable(false);
        setCloseStrategy(GFrameCloseStrategy.EXIT_ON_CLOSE);
        GLabel lPosition = new GLabel(getWidth() * 0.05F, getHeight() * 0.88F + getHeight() * 0.035F, getWidth(), getHeight() * 0.07F, bannerFont);
        lPosition.setText(strings.get(1));
        lPosition.setId("lPosition");
        GLabel lOrigin = new GLabel(getWidth() * 0.05F, getHeight() * 0.8F + getHeight() * 0.035F, getWidth(), getHeight() * 0.07F, bannerFont);
        lOrigin.setText(strings.get(2));
        lOrigin.setId("lOrigin");
        GLabel lSrc = new GLabel(getWidth() * 0.05F, getHeight() * 0.72F + getHeight() * 0.035F, getWidth(), getHeight() * 0.07F, bannerFont);
        lSrc.setText(strings.get(3));
        lSrc.setId("lSrc");
        GLabel lSize = new GLabel(getWidth() * 0.05F, getHeight() * 0.64F + getHeight() * 0.035F, getWidth(), getHeight() * 0.07F, bannerFont);
        lSize.setText(strings.get(4));
        lSize.setId("lSize");
        GLabel lScale = new GLabel(getWidth() * 0.05F, getHeight() * 0.56F + getHeight() * 0.035F, getWidth(), getHeight() * 0.07F, bannerFont);
        lScale.setText(strings.get(5));
        lScale.setId("lScale");
        GLabel lRotation = new GLabel(getWidth() * 0.05F, getHeight() * 0.48F + getHeight() * 0.035F, getWidth(), getHeight() * 0.07F, bannerFont);
        lRotation.setText(strings.get(6));
        lRotation.setId("lRotation");
        GLabel lVisible = new GLabel(getWidth() * 0.05F, getHeight() * 0.4F + getHeight() * 0.035F, getWidth(), getHeight() * 0.07F, bannerFont);
        lVisible.setText(strings.get(7));
        lVisible.setId("lVisible");
        GLabel lTint = new GLabel(getWidth() * 0.05F, getHeight() * 0.32F + getHeight() * 0.035F, getWidth(), getHeight() * 0.07F, bannerFont);
        lTint.setText(strings.get(8));
        lTint.setId("lTint");
        GLabel lColorOffset = new GLabel(getWidth() * 0.05F, getHeight() * 0.24F + getHeight() * 0.035F, getWidth(), getHeight() * 0.07F, bannerFont);
        lColorOffset.setText(strings.get(9));
        lColorOffset.setId("lColorOffset");
        GLabel lInterpolation = new GLabel(getWidth() * 0.05F, getHeight() * 0.16F + getHeight() * 0.035F, getWidth(), getHeight() * 0.07F, bannerFont);
        lInterpolation.setText(strings.get(10));
        lInterpolation.setId("lInterpolation");

        addElement(lPosition);
        addElement(lOrigin);
        addElement(lSrc);
        addElement(lSize);
        addElement(lScale);
        addElement(lRotation);
        addElement(lVisible);
        addElement(lTint);
        addElement(lColorOffset);
        addElement(lInterpolation);

        GButton x = new GButton(getWidth() * 0.35F, lPosition.getY(false) - getHeight() * 0.03F, getWidth() * 0.1F, getWidth() * 0.1F, bannerFont) {
            @Override
            public void onClick() {
                new SinglePropertyAdjustWindow(bannerFont, xPosFunc, SinglePropertyAdjustWindow.FuncType.FLOAT, lPosition.getText() + " x");
            }
        };
        x.setFgTexture(new Texture("buttons/reset_activated.png"));
        x.setId("x");
        x.setText("");

        GButton y = new GButton(getWidth() * 0.55F + 3, lPosition.getY(false) - getHeight() * 0.03F, getWidth() * 0.1F, getWidth() * 0.1F, bannerFont) {
            @Override
            public void onClick() {
                new SinglePropertyAdjustWindow(bannerFont, yPosFunc, SinglePropertyAdjustWindow.FuncType.FLOAT, lPosition.getText() + " y");
            }
        };
        y.setFgTexture(new Texture("buttons/reset_activated.png"));
        y.setId("y");
        y.setText("");

        GButton xOrigin = new GButton(getWidth() * 0.35F, lOrigin.getY(false) - getHeight() * 0.03F, getWidth() * 0.1F, getWidth() * 0.1F, bannerFont) {
            @Override
            public void onClick() {
                new SinglePropertyAdjustWindow(bannerFont, xOriginFunc, SinglePropertyAdjustWindow.FuncType.FLOAT, lOrigin.getText() + " x");
            }
        };
        xOrigin.setFgTexture(new Texture("buttons/reset_activated.png"));
        xOrigin.setId("xOrigin");
        xOrigin.setText("");

        GButton yOrigin = new GButton(getWidth() * 0.55F + 3, lOrigin.getY(false) - getHeight() * 0.03F, getWidth() * 0.1F, getWidth() * 0.1F, bannerFont) {
            @Override
            public void onClick() {
                new SinglePropertyAdjustWindow(bannerFont, yOriginFunc, SinglePropertyAdjustWindow.FuncType.FLOAT, lOrigin.getText() + " y");
            }
        };
        yOrigin.setFgTexture(new Texture("buttons/reset_activated.png"));
        yOrigin.setId("yOrigin");
        yOrigin.setText("");

        GButton xSrc = new GButton(getWidth() * 0.35F, lSrc.getY(false) - getHeight() * 0.03F, getWidth() * 0.1F, getWidth() * 0.1F, bannerFont) {
            @Override
            public void onClick() {
                new SinglePropertyAdjustWindow(bannerFont, xSrcFunc, SinglePropertyAdjustWindow.FuncType.INT, lSrc.getText() + " x");
            }
        };
        xSrc.setFgTexture(new Texture("buttons/reset_activated.png"));
        xSrc.setId("xSrc");
        xSrc.setText("");

        GButton ySrc = new GButton(getWidth() * 0.55F + 3, lSrc.getY(false) - getHeight() * 0.03F, getWidth() * 0.1F, getWidth() * 0.1F, bannerFont) {
            @Override
            public void onClick() {
                new SinglePropertyAdjustWindow(bannerFont, ySrcFunc, SinglePropertyAdjustWindow.FuncType.INT, lSrc.getText() + " y");
            }
        };
        ySrc.setFgTexture(new Texture("buttons/reset_activated.png"));
        ySrc.setId("ySrc");
        ySrc.setText("");

        GButton width = new GButton(getWidth() * 0.35F, lSize.getY(false) - getHeight() * 0.03F, getWidth() * 0.1F, getWidth() * 0.1F, bannerFont) {
            @Override
            public void onClick() {
                new SinglePropertyAdjustWindow(bannerFont, srcWidthFunc, SinglePropertyAdjustWindow.FuncType.INT, lSize.getText() + " x");
            }
        };
        width.setFgTexture(new Texture("buttons/reset_activated.png"));
        width.setId("width");
        width.setText("");

        GButton height = new GButton(getWidth() * 0.55F + 3, lSize.getY(false) - getHeight() * 0.03F, getWidth() * 0.1F, getWidth() * 0.1F, bannerFont) {
            @Override
            public void onClick() {
                new SinglePropertyAdjustWindow(bannerFont, srcHeightFunc, SinglePropertyAdjustWindow.FuncType.INT, lSize.getText() + " y");
            }
        };
        height.setFgTexture(new Texture("buttons/reset_activated.png"));
        height.setId("height");
        height.setText("");

        GButton xScale = new GButton(getWidth() * 0.35F, lScale.getY(false) - getHeight() * 0.03F, getWidth() * 0.1F, getWidth() * 0.1F, bannerFont) {
            @Override
            public void onClick() {
                new SinglePropertyAdjustWindow(bannerFont, xScaleFunc, SinglePropertyAdjustWindow.FuncType.FLOAT, lSize.getText() + " x");
            }
        };
        xScale.setFgTexture(new Texture("buttons/reset_activated.png"));
        xScale.setId("xScale");
        xScale.setText("");

        GButton yScale = new GButton(getWidth() * 0.55F + 3, lScale.getY(false) - getHeight() * 0.03F, getWidth() * 0.1F, getWidth() * 0.1F, bannerFont) {
            @Override
            public void onClick() {
                new SinglePropertyAdjustWindow(bannerFont, yScaleFunc, SinglePropertyAdjustWindow.FuncType.FLOAT, lSize.getText() + " y");
            }
        };
        yScale.setFgTexture(new Texture("buttons/reset_activated.png"));
        yScale.setId("yScale");
        yScale.setText("");

        GButton rotation = new GButton(getWidth() * 0.35F, lRotation.getY(false) - getHeight() * 0.03F, getWidth() * 0.1F, getWidth() * 0.1F, bannerFont) {
            @Override
            public void onClick() {
                new SinglePropertyAdjustWindow(bannerFont, rotationFunc, SinglePropertyAdjustWindow.FuncType.FLOAT, lRotation.getText());
            }
        };
        rotation.setFgTexture(new Texture("buttons/reset_activated.png"));
        rotation.setId("rotation");
        rotation.setText("");

        GButton visible = new GButton(getWidth() * 0.35F, lVisible.getY(false) - getHeight() * 0.03F, getWidth() * 0.1F, getWidth() * 0.1F, bannerFont) {
            @Override
            public void onClick() {
                new SinglePropertyAdjustWindow(bannerFont, visibleFunc, SinglePropertyAdjustWindow.FuncType.BOOLEAN, lVisible.getText());
            }
        };
        visible.setFgTexture(new Texture("buttons/reset_activated.png"));
        visible.setId("visible");
        visible.setText("");

        GButton tintR = new GButton(getWidth() * 0.25F, lTint.getY(false) - getHeight() * 0.03F, getWidth() * 0.1F, getWidth() * 0.1F, bannerFont) {
            @Override
            public void onClick() {
                new SinglePropertyAdjustWindow(bannerFont, tintRFunc, SinglePropertyAdjustWindow.FuncType.INT, lTint.getText() + " R");
            }
        };
        tintR.setFgTexture(new Texture("buttons/reset_activated.png"));
        tintR.setId("tintR");
        tintR.setText("");

        GButton tintG = new GButton(getWidth() * 0.4F + 3, lTint.getY(false) - getHeight() * 0.03F, getWidth() * 0.1F, getWidth() * 0.1F, bannerFont) {
            @Override
            public void onClick() {
                new SinglePropertyAdjustWindow(bannerFont, tintGFunc, SinglePropertyAdjustWindow.FuncType.INT, lTint.getText() + " G");
            }
        };
        tintG.setFgTexture(new Texture("buttons/reset_activated.png"));
        tintG.setId("tintG");
        tintG.setText("");

        GButton tintB = new GButton(getWidth() * 0.55F + 6, lTint.getY(false) - getHeight() * 0.03F, getWidth() * 0.1F, getWidth() * 0.1F, bannerFont) {
            @Override
            public void onClick() {
                new SinglePropertyAdjustWindow(bannerFont, tintBFunc, SinglePropertyAdjustWindow.FuncType.INT, lTint.getText() + " B");
            }
        };
        tintB.setFgTexture(new Texture("buttons/reset_activated.png"));
        tintB.setId("tintB");
        tintB.setText("");

        GButton tintA = new GButton(getWidth() * 0.7F + 9, lTint.getY(false) - getHeight() * 0.03F, getWidth() * 0.1F, getWidth() * 0.1F, bannerFont) {
            @Override
            public void onClick() {
                new SinglePropertyAdjustWindow(bannerFont, tintAFunc, SinglePropertyAdjustWindow.FuncType.INT, lTint.getText() + " A");
            }
        };
        tintA.setFgTexture(new Texture("buttons/reset_activated.png"));
        tintA.setId("tintA");
        tintA.setText("");

        GButton offsetR = new GButton(getWidth() * 0.45F, lColorOffset.getY(false) - getHeight() * 0.03F, getWidth() * 0.1F, getWidth() * 0.1F, bannerFont) {
            @Override
            public void onClick() {
                new SinglePropertyAdjustWindow(bannerFont, colorOffsetRCurve, SinglePropertyAdjustWindow.FuncType.INT, lColorOffset.getText() + " R");
            }
        };
        offsetR.setFgTexture(new Texture("buttons/reset_activated.png"));
        offsetR.setId("offsetR");
        offsetR.setText("");

        GButton offsetG = new GButton(getWidth() * 0.6F + 3, lColorOffset.getY(false) - getHeight() * 0.03F, getWidth() * 0.1F, getWidth() * 0.1F, bannerFont) {
            @Override
            public void onClick() {
                new SinglePropertyAdjustWindow(bannerFont, colorOffsetGCurve, SinglePropertyAdjustWindow.FuncType.INT, lColorOffset.getText() + " G");
            }
        };
        offsetG.setFgTexture(new Texture("buttons/reset_activated.png"));
        offsetG.setId("offsetG");
        offsetG.setText("");

        GButton offsetB = new GButton(getWidth() * 0.75F + 6, lColorOffset.getY(false) - getHeight() * 0.03F, getWidth() * 0.1F, getWidth() * 0.1F, bannerFont) {
            @Override
            public void onClick() {
                new SinglePropertyAdjustWindow(bannerFont, colorOffsetBCurve, SinglePropertyAdjustWindow.FuncType.INT, lColorOffset.getText() + " B");
            }
        };
        offsetB.setFgTexture(new Texture("buttons/reset_activated.png"));
        offsetB.setId("offsetB");
        offsetB.setText("");

        GButton interpolation = new GButton(getWidth() * 0.3F, lInterpolation.getY(false) - getHeight() * 0.03F, getWidth() * 0.1F, getWidth() * 0.1F, bannerFont) {
            @Override
            public void onClick() {
                new SinglePropertyAdjustWindow(bannerFont, interpolationFunc, SinglePropertyAdjustWindow.FuncType.BOOLEAN, lInterpolation.getText());
            }
        };
        interpolation.setFgTexture(new Texture("buttons/reset_activated.png"));
        interpolation.setId("interpolation");
        interpolation.setText("");

        addElement(x);
        addElement(y);
        addElement(xOrigin);
        addElement(yOrigin);
        addElement(xSrc);
        addElement(ySrc);
        addElement(width);
        addElement(height);
        addElement(xScale);
        addElement(yScale);
        addElement(rotation);
        addElement(visible);
        addElement(tintR);
        addElement(tintG);
        addElement(tintB);
        addElement(tintA);
        addElement(offsetR);
        addElement(offsetG);
        addElement(offsetB);
        addElement(interpolation);

        GLabel lLength = new GLabel(getWidth() * 0.05F, getHeight() * 0.08F + getHeight() * 0.035F, getWidth(), getHeight() * 0.07F, bannerFont);
        lLength.setText(strings.get(12));
        lLength.setId("lLength");
        addElement(lLength);

        GTextField tLength = new GTextField(getWidth() * 0.35F, getHeight() * 0.085F, getWidth() * 0.15F, getHeight() * 0.05F, bannerFont) {
            @Override
            public boolean keyDown(int keyCode) {
                if (keyCode == Input.Keys.ENTER && FormManager.getInstance().getEventHooks().getCurrentFocusedElement() == this) {
                    if (getText().length() > 0 && getText().length() < 10) {
                        FormManager.getInstance().getEventHooks().setCurrentFocusedElement(getParent());
                        confirmed = true;
                        FormManager.getInstance().removeContainer(AdjustKeyframePropertyWindow.this);
                    } else {
                        new MessageBox(strings.get(15), strings.get(17), FontHelper.getFont(FontKeys.SIM_HEI_14));
                    }
                    return true;
                }
                return super.keyDown(keyCode);
            }

            @Override
            public void deactivate() {
                if (getText().length() > 0 && getText().length() < 10) {
                    endFrameIndex = startFrameIndex + (int) Double.parseDouble(getText());
                }
            }
        };
        tLength.setId("tLength");
        tLength.setCharFilter("[0-9]");
        addElement(tLength);

        GButton confirm = new GButton(getWidth() * 0.5F, 10, getWidth() * 0.2F, 20, FontHelper.getFont(FontKeys.SIM_HEI_14)) {
            @Override
            public void onClick() {
                confirmed = true;
                if (tLength.getText().length() > 0 && tLength.getText().length() < 10) {
                    endFrameIndex = startFrameIndex + (int) Double.parseDouble(tLength.getText());
                    FormManager.getInstance().removeContainer(AdjustKeyframePropertyWindow.this);
                } else {
                    new MessageBox(strings.get(15), strings.get(17), FontHelper.getFont(FontKeys.SIM_HEI_14));
                }
            }
        };
        confirm.setText(strings.get(13));
        confirm.setBackground(new Color(0, 47.0F / 255.0F, 147.0F / 255.0F, 1.0F));
        confirm.setBorderWidth(2);
        confirm.setBorder(Color.LIGHT_GRAY.cpy());
        GButton cancel = new GButton(getWidth() * 0.75F, 10, getWidth() * 0.2F, 20, FontHelper.getFont(FontKeys.SIM_HEI_14)) {
            @Override
            public void onClick() {
                FormManager.getInstance().removeContainer(AdjustKeyframePropertyWindow.this);
            }
        };
        cancel.setText(strings.get(14));
        cancel.setBackground(Color.LIGHT_GRAY.cpy());
        cancel.setBorderWidth(2);
        cancel.setBorder(Color.LIGHT_GRAY.cpy());

        addElement(confirm);
        addElement(cancel);

        GLabel lSource = new GLabel(getWidth() * 0.45F, getHeight() * 0.16F + getHeight() * 0.035F, getWidth(), getHeight() * 0.07F, bannerFont);
        lSource.setText(strings.get(11));
        lSource.setId("lSource");
        addElement(lSource);

        GButton btnSource = new GButton(getWidth() * 0.7F, getHeight() * 0.16F + getHeight() * 0.02F, getWidth() * 0.2F, getHeight() * 0.05F, bannerFont) {
            @Override
            public void onClick() {
                List<Track> tracks = new ArrayList<>(Project.currentProject.getTracks());
                OptionWindow optionWindow = new OptionWindow(strings.get(18), tracks.stream().map(Track::getName).collect(Collectors.toList()), bannerFont, 0);
                optionWindow.setConfirmCallback(index -> {
                    this.setText(tracks.get(index).getName());
                    targetTrack = tracks.get(index);
                });
            }
        };
        btnSource.setText("");
        btnSource.setId("btnSource");
        btnSource.setBackground(new Color(0, 47.0F / 255.0F, 147.0F / 255.0F, 1.0F));
        addElement(btnSource);
    }

    @Override
    public void dispose() {
        super.dispose();
        if (confirmed) {
            List<String> strings = LocalizedStrings.getStrings("AdjustKeyframePropertyWindow");
            if (targetTrack != null) {
                List<KeyFrame> dstBackup = new ArrayList<>();
                KeyFrame lastFrame = null;
                for (int i=startFrameIndex;i<endFrameIndex;i++) {
                    KeyFrame dst = targetTrack.getContent(Project.currentProject.getCurrentAnimation().getName()).getKeyFrameAt(i);
                    if (dst != null && dst != lastFrame) {
                        dstBackup.add(dst.makeCopy());
                        lastFrame = dst;
                    }
                }
                doRefactor();
                Operation operation = new Operation() {
                    @Override
                    public void undo() {
                        KeyFrame keyFrame = targetTrack.getContent(Project.currentProject.getCurrentAnimation().getName()).getKeyFrameAt(startFrameIndex);
                        int index = targetTrack.getContent(Project.currentProject.getCurrentAnimation().getName()).getKeyFrames().indexOf(keyFrame);
                        for (int i=0;i<dstBackup.size();i++) {
                            targetTrack.getContent(Project.currentProject.getCurrentAnimation().getName()).getKeyFrames().set(index + i, dstBackup.get(i));
                        }
                    }

                    @Override
                    public void redo() {
                        doRefactor();
                    }
                };
                operation.setName(strings.get(0));
                historyPanel.addOperation(operation);
            } else {
                new MessageBox(strings.get(15), strings.get(16), FontHelper.getFont(FontKeys.SIM_HEI_14));
            }
        }
    }

    private void doRefactor() {
        KeyFrame lastFrame = null;
        for (int i=startFrameIndex;i<endFrameIndex;i++) {
            KeyFrame dst = targetTrack.getContent(Project.currentProject.getCurrentAnimation().getName()).getKeyFrameAt(i);
            if (dst != null && lastFrame != dst) {
                dst.xPosition = dst.xPosition + xPosFunc.item1;
                dst.xPosition = (dst.xPosition - xPosFunc.item2) * (xPosFunc.item3 / 100.0F) + xPosFunc.item2;
                dst.yPosition = dst.yPosition + yPosFunc.item1;
                dst.yPosition = (dst.yPosition - yPosFunc.item2) * (yPosFunc.item3 / 100.0F) + yPosFunc.item2;
                dst.xPivot = dst.xPivot + xOriginFunc.item1;
                dst.xPivot = (dst.xPivot - xOriginFunc.item2) * (xOriginFunc.item3 / 100.0F) + xOriginFunc.item2;
                dst.yPivot = dst.yPivot + yOriginFunc.item1;
                dst.yPivot = (dst.yPivot - yOriginFunc.item2) * (yOriginFunc.item3 / 100.0F) + yOriginFunc.item2;
                dst.xCrop = dst.xCrop + xSrcFunc.item1;
                dst.xCrop = (int) ((dst.xCrop - xSrcFunc.item2) * (xSrcFunc.item3 / 100.0F) + xSrcFunc.item2);
                dst.yCrop = dst.yCrop + ySrcFunc.item1;
                dst.yCrop = (int) ((dst.yCrop - ySrcFunc.item2) * (ySrcFunc.item3 / 100.0F) + ySrcFunc.item2);
                dst.width = dst.width + srcWidthFunc.item1;
                dst.width = (int) ((dst.width - srcWidthFunc.item2) * (srcWidthFunc.item3 / 100.0F) + srcWidthFunc.item2);
                dst.height = dst.height + srcHeightFunc.item1;
                dst.height = (int) ((dst.height - srcHeightFunc.item2) * (srcHeightFunc.item3 / 100.0F) + srcHeightFunc.item2);
                dst.xScale = dst.xScale + xScaleFunc.item1;
                dst.xScale = (dst.xScale - xScaleFunc.item2) * (xScaleFunc.item3 / 100.0F) + xScaleFunc.item2;
                dst.yScale = dst.yScale + yScaleFunc.item1;
                dst.yScale = (dst.yScale - yScaleFunc.item2) * (yScaleFunc.item3 / 100.0F) + yScaleFunc.item2;
                dst.rotation = dst.rotation + rotationFunc.item1;
                dst.rotation = (dst.rotation - rotationFunc.item2) * (rotationFunc.item3 / 100.0F) + rotationFunc.item2;

                if (visibleFunc.item1) {
                    dst.visible = !dst.visible;
                } else if (visibleFunc.item2) {
                    dst.visible = true;
                } else if (visibleFunc.item3) {
                    dst.visible = false;
                }

                dst.tint.r = dst.tint.r + tintRFunc.item1 / 255.0F;
                dst.tint.r = (dst.tint.r - tintRFunc.item2 / 255.0F) * (tintRFunc.item3 / 100.0F) + tintRFunc.item2 / 255.0F;
                dst.tint.g = dst.tint.g + tintGFunc.item1 / 255.0F;
                dst.tint.g = (dst.tint.g - tintGFunc.item2 / 255.0F) * (tintGFunc.item3 / 100.0F) + tintGFunc.item2 / 255.0F;
                dst.tint.b = dst.tint.b + tintBFunc.item1 / 255.0F;
                dst.tint.b = (dst.tint.b - tintBFunc.item2 / 255.0F) * (tintBFunc.item3 / 100.0F) + tintBFunc.item2 / 255.0F;
                dst.tint.a = dst.tint.a + tintAFunc.item1 / 255.0F;
                dst.tint.a = (dst.tint.a - tintAFunc.item2 / 255.0F) * (tintAFunc.item3 / 100.0F) + tintAFunc.item2 / 255.0F;

                dst.colorOffset.r = dst.colorOffset.r + colorOffsetRCurve.item1 / 255.0F;
                dst.colorOffset.r = (dst.colorOffset.r - colorOffsetRCurve.item2 / 255.0F) * (colorOffsetRCurve.item3 / 100.0F) + colorOffsetRCurve.item2 / 255.0F;
                dst.colorOffset.g = dst.colorOffset.g + colorOffsetGCurve.item1 / 255.0F;
                dst.colorOffset.g = (dst.colorOffset.g - colorOffsetGCurve.item2 / 255.0F) * (colorOffsetGCurve.item3 / 100.0F) + colorOffsetGCurve.item2 / 255.0F;
                dst.colorOffset.b = dst.colorOffset.b + colorOffsetBCurve.item1 / 255.0F;
                dst.colorOffset.b = (dst.colorOffset.b - colorOffsetBCurve.item2 / 255.0F) * (colorOffsetBCurve.item3 / 100.0F) + colorOffsetBCurve.item2 / 255.0F;

                if (interpolationFunc.item1) {
                    dst.interpolated = !dst.interpolated;
                } else if (interpolationFunc.item2) {
                    dst.interpolated = true;
                } else if (interpolationFunc.item3) {
                    dst.interpolated = false;
                }
                lastFrame = dst;
            }
        }
    }
}
